/**
 * 
 */
package com.ubo.java.model.classifier;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.ubo.java.model.EVisibility;
import com.ubo.java.model.PackageModel;
import com.ubo.java.model.comment.Comment;
import com.ubo.java.model.declaration.Attribut;
import com.ubo.java.model.methode.Constructor;
import com.ubo.java.model.methode.Method;
import com.ubo.java.model.methode.Prototype;
import com.ubo.transform.java.IJavaVisitor;

/**
 * 
 * @author saludegu
 * 
 */
public class ClassModel extends AClassifier {

	/**
	 * Classe étendue par cette classe.
	 */
	protected ClassModel mExtendedClasse;

	/**
	 * Set des méthodes contenues dans une classe.
	 */
	protected Set<Method> mMethodeSet;

	/**
	 * Set des attributs de la classe.
	 */
	protected Set<Attribut> mAttributSet;

	/**
	 * Set des prototypes de méthodes (class abstraites).
	 */
	protected Set<Prototype> mPrototypes;

	/**
	 * Constructeur de la classe.
	 */
	protected Set<Constructor> mConstructor;

	/**
	 * 
	 * Constructor
	 * 
	 */
	public ClassModel(String className, PackageModel packageClass,
			EVisibility visibility) {
		super(className, packageClass, visibility);
		mComment = new Comment(new StringBuffer("* Class " + className + "\n"));
		mComment.setAuthor();
	}

	/**
	 * 
	 * Constructor
	 * 
	 */
	public ClassModel(String className, PackageModel packageClass,
			EVisibility visibility, Comment comment) {
		super(className, packageClass, visibility);
		mComment = comment;
	}

	/**
	 * Ajout d'une collection d'attributs à la classe.
	 * 
	 * @param attributs
	 */
	public void addAllAttr(Collection<Attribut> attributs) {
		if (mAttributSet == null)
			mAttributSet = new HashSet<Attribut>(0);
		mAttributSet.addAll(attributs);
	}

	/**
	 * Ajout d'une collection d'attributs à la classe.
	 * 
	 * @param attributs
	 */
	public void addAllProto(Collection<Prototype> prototypes) {
		if (mPrototypes == null)
			mPrototypes = new HashSet<Prototype>(0);
		mPrototypes.addAll(prototypes);
	}

	/**
	 * Ajout d'une collection de constructeurs à la classe.
	 * 
	 * @param attributs
	 */
	public void addAllConstructors(Collection<Constructor> constructors) {
		if (mConstructor == null)
			mConstructor = new HashSet<Constructor>(0);
		mConstructor.addAll(constructors);
	}

	/**
	 * Ajout d'un constructeur à la classe.
	 * 
	 * @param attributs
	 */
	public void addConstructor(Constructor constructor) {
		if (mConstructor == null)
			mConstructor = new HashSet<Constructor>(0);
		mConstructor.add(constructor);
	}

	/**
	 * Ajout d'une collection de méthode à la classe.
	 * 
	 * @param methods
	 */
	public void addAllMeth(Collection<Method> methods) {
		if (mMethodeSet == null)
			mMethodeSet = new HashSet<Method>(0);
		mMethodeSet.addAll(methods);
	}

	/**
	 * Ajout de la classe héritée.
	 * 
	 * @param classToExtend
	 */
	public void extendClass(ClassModel classToExtend) {
		mExtendedClasse = classToExtend;
		if (mExtendedClasse.getPrototypes() != null
				&& mExtendedClasse.getPrototypes().size() > 0) {
			if (mMethodeSet == null)
				mMethodeSet = new HashSet<Method>(0);
			for (Prototype proto : mExtendedClasse.getPrototypes()) {
				mMethodeSet.add(new Method(proto.getName(), proto
						.getModifierList(), proto.getVisibility(), proto
						.getListClassThrowns(), proto.getParameterList(), proto
						.getType(), true));
			}
		}
	}

	/**
	 * Ajout d'une collection d'interfaces implémentés à la classe.
	 * 
	 * @param interfaces
	 */
	@Override
	public void implementsInterfaces(Collection<Interface> interfaces) {
		if (mInterfaceImplemented == null)
			mInterfaceImplemented = new HashSet<Interface>(0);
		mInterfaceImplemented.addAll(interfaces);
		List<Method> methods = new ArrayList<Method>(0);
		for (Interface currInterface : interfaces) {
			methods.addAll(getPrototypesToImplement(currInterface));
		}
		// Récupération des prototypes et création des méthodes.
		if (mMethodeSet == null)
			mMethodeSet = new HashSet<Method>(0);
		mMethodeSet.addAll(methods);
	}

	/**
	 * Ajout d'une collection d'interfaces implémentés à la classe.
	 * 
	 * @param interfaces
	 */
	public void implementsInterfaces(Interface classifier) {
		if (mInterfaceImplemented == null)
			mInterfaceImplemented = new HashSet<Interface>(0);
		mInterfaceImplemented.add(classifier);
		List<Method> methods = new ArrayList<Method>(0);
		methods.addAll(getPrototypesToImplement(classifier));
		// Récupération des prototypes et création des méthodes.
		if (mMethodeSet == null)
			mMethodeSet = new HashSet<Method>(0);
		mMethodeSet.addAll(methods);
	}

	/**
	 * Getter des prototypes à implémenter.
	 * 
	 * @param currInterface
	 * @return
	 */
	public List<Method> getPrototypesToImplement(Interface currInterface) {
		List<Method> methods = new ArrayList<Method>(0);
		if (currInterface.getInterfaceImplemented() != null
				&& currInterface.getInterfaceImplemented().size() > 0) {
			for (Interface inter : currInterface.getInterfaceImplemented())
				methods.addAll(getPrototypesToImplement(inter));
		}
		if (currInterface.getPrototypes() != null
				&& currInterface.getPrototypes().size() > 0) {
			for (Prototype prototype : currInterface.getPrototypes()) {
				Comment newMethodComment = new Comment(new StringBuffer(
						"\t*\n\t"));
				newMethodComment.setSee(currInterface.printPath(),
						prototype.getName());
				methods.add(new Method(prototype.getName(), prototype
						.getModifierList(), prototype.getVisibility(),
						prototype.getListClassThrowns(), prototype
								.getParameterList(), prototype.getType(), true,
						newMethodComment));
			}
		}
		return methods;
	}

	/**
	 * 
	 * @return Constructors.
	 */
	public Set<Constructor> getConstructors() {
		if (mConstructor == null)
			mConstructor = new HashSet<Constructor>(0);
		Constructor defaultConstructor = new Constructor(EVisibility.PUBLIC,
				null, this);
		mConstructor.add(defaultConstructor);
		return mConstructor;
	}

	/**
	 * @return the mExtendedClasse
	 */
	public ClassModel getExtendedClasse() {
		return mExtendedClasse;
	}

	/**
	 * @return the mMethodeSet
	 */
	public Set<Method> getMethodeSet() {
		return mMethodeSet;
	}

	/**
	 * @return the mAttributSet
	 */
	public Set<Attribut> getAttributSet() {
		return mAttributSet;
	}

	/**
	 * @return the mPrototypes
	 */
	public Set<Prototype> getPrototypes() {
		return mPrototypes;
	}

	/**
	 * @see com.ubo.transform.java.IJavaGenerable#generate(com.ubo.transform.java.IJavaVisitor)
	 */
	@Override
	public void generate(IJavaVisitor<?> generator) {
		generator.generate(this);
	}

	/**
	 * 
	 */
	@Override
	public void extendsClassifier(IClassifier classifier) {
		classifier.extendsClassifier(this);
	}

	@Override
	public void implementsClassifier(IClassifier classifier) {
		classifier.implementsClassifier(this);
	}

	@Override
	public void extendsClassifier(ClassModel classifier) {
		classifier.extendClass(this);
	}

	@Override
	public void implementsClassifier(Interface classifier) {
		if (mInterfaceImplemented == null)
			mInterfaceImplemented = new HashSet<Interface>();
		mInterfaceImplemented.add(classifier);
	}

	public void extendsClassifier(Interface classifier) {
	}

	public void implementsClassifier(ClassModel classifier) {

	}

}
